package com.mm.controller.mp;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.AopLog;
import com.mm.base.annotation.AutoIdempotent;
import com.mm.base.annotation.DistributedLock;
import com.mm.base.annotation.VerifyToken;
import com.mm.base.exception.MuMuException;
import com.mm.base.redis.RedisLock;
import com.mm.util.result.DPage;
import com.mm.util.result.DResult;
import com.mm.util.result.ResultCode;
import com.mm.domain.common.DCommonCode;
import com.mm.domain.taxi.DTaxiAddressInfo;
import com.mm.domain.taxi.DTaxiOrderInfo;
import com.mm.domain.taxi.DUserOrderRelation;
import com.mm.serivce.common.IDCommonCodeService;
import com.mm.serivce.mp.impl.TaxiOrderInfoServiceImpl;
import com.mm.serivce.taxi.IDTaxiAddressInfoService;
import com.mm.serivce.taxi.IDUserOrderRelationService;
import com.mm.util.common.CreateOrderUtil;
import com.mm.util.common.RedisUtil;
import com.mm.util.common.CommonKey;
import com.mm.util.common.RedisKey;
import com.mm.vo.mp.TaxiOrderReq;
import com.mm.vo.mp.TaxiOrderRep;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.util.Objects;

/**
 * 描述: 小程序用户订单
 *
 * @author: yanglin
 * @Date: 2021-08-19-9:48
 * @Version: 1.0
 */
@Api(value = "/mp/o/v1", tags = {"小程序用户订单"})
@Slf4j
@VerifyToken(type = 1)
@AutoIdempotent
@RestController
@RequestMapping("/mp/o/v1")
@AopLog(type = "小程序用户订单", stackTraceOnErr = true)
public class OrderController {

    private final RedisUtil redisUtil;
    private final RedisLock redisLock;
    private final TaxiOrderInfoServiceImpl orderInfoService;
    private final IDTaxiAddressInfoService addressInfoService;
    private final IDUserOrderRelationService uoRelationService;
    private final IDCommonCodeService codeService;

    public OrderController(RedisUtil redisUtil, RedisLock redisLock, TaxiOrderInfoServiceImpl orderInfoService, IDTaxiAddressInfoService addressInfoService, IDUserOrderRelationService uoRelationService, IDCommonCodeService codeService) {
        this.redisUtil = redisUtil;
        this.redisLock = redisLock;
        this.orderInfoService = orderInfoService;
        this.addressInfoService = addressInfoService;
        this.uoRelationService = uoRelationService;
        this.codeService = codeService;
    }


    /**
     * 用户订单列表接口
     *
     * @param orderReq
     * @param page
     * @param limit
     * @return
     */
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "body", dataType = "TaxiOrderReq", dataTypeClass = TaxiOrderReq.class, name = "orderReq", value = "", required = true),
            @ApiImplicitParam(paramType = "query", dataType = "int", dataTypeClass = Integer.class, name = "page", value = "", required = true),
            @ApiImplicitParam(paramType = "query", dataType = "int", dataTypeClass = Integer.class, name = "limit", value = "", required = true)
    })
    @ApiOperation(value = "用户订单列表接口", notes = "用户订单列表接口", httpMethod = "POST")
    @PostMapping("/taxiOrderList")
    public DResult taxiOrderList(@RequestBody TaxiOrderReq orderReq, @RequestParam int page, @RequestParam int limit) {
        // 根据用户openId查询订单信息
        if (Objects.isNull(orderReq)) {
            throw new MuMuException("订单参数不能为空!");
        }
        Page<TaxiOrderRep> orderRepPage = orderInfoService.queryTaxiOrderWechat(page, limit, orderReq);
        DPage<TaxiOrderRep> orderRepDPage = DPage.to(orderRepPage);
        return DResult.of(orderRepDPage);
    }

    /**
     * 用户订单详情接口
     *
     * @param orderReq
     * @return
     */
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "body", dataType = "TaxiOrderReq", dataTypeClass = TaxiOrderReq.class, name = "orderReq", value = "", required = true)
    })
    @ApiOperation(value = "用户订单详情接口", notes = "用户订单详情接口", httpMethod = "POST")
    @PostMapping("/taxiOrderDetail")
    public DResult taxiOrderDetail(@RequestBody TaxiOrderReq orderReq) {
        // 根据用户openId查询订单信息
        if (Objects.isNull(orderReq)) {
            throw new MuMuException("订单参数不能为空!");
        }
        TaxiOrderRep orderRepPage = orderInfoService.queryTaxiOrderWechatDetail(orderReq);
        return DResult.of(orderRepPage);
    }

    /**
     * 乘客创建订单/立即打车接口
     *
     * @param orderReq
     * @return
     */
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "body", dataType = "TaxiOrderReq", dataTypeClass = TaxiOrderReq.class, name = "orderReq", value = "", required = true)
    })
    @ApiOperation(value = "乘客创建订单/立即打车接口", notes = "乘客创建订单/立即打车接口", httpMethod = "POST")
    @Transactional
    @DistributedLock
    @PostMapping("/createTaxiOrder")
    public DResult createTaxiOrder(@RequestBody TaxiOrderReq orderReq) {
        boolean result = false;
        TaxiOrderRep orderVo = new TaxiOrderRep();
        // 起点
        String taxiFirst = orderReq.getTaxiFirst();
        String taxiFirstDetail = orderReq.getTaxiFirstDetail();
        String taxiFirstXyz = orderReq.getTaxiFirstXyz();
        // 终点
        String taxiLast = orderReq.getTaxiLast();
        String taxiLastDetail = orderReq.getTaxiLastDetail();
        String taxiLastXyz = orderReq.getTaxiLastXyz();
        // 预估费用
        Integer taxiCosts = orderReq.getTaxiCosts();
        // 预估乘客数
        Integer taxiSeatNum = orderReq.getTaxiSeatNum();
        // 打车用户OpenId
        String mOpenId = orderReq.getMOpenId();
        // 创建打车地址
        DTaxiAddressInfo addressInfo = DTaxiAddressInfo.builder()
                .taxiFirst(taxiFirst).taxiFirstDetail(taxiFirstDetail)
                .taxiLast(taxiLast).taxiLastDetail(taxiLastDetail)
                .taxiFirstXyz(taxiFirstXyz).taxiLastXyz(taxiLastXyz)
                .taxiCosts(taxiCosts).taxiSeatNum(taxiSeatNum).build();
        result = addressInfoService.save(addressInfo);
        // 创建打车订单
        DTaxiOrderInfo orderInfo = DTaxiOrderInfo.builder()
                .orderCode(CreateOrderUtil.generateOrderNo("mp"))
                .orderPrice(taxiCosts).orderStatus(CommonKey.ORDER_STATUS_10.getValue())
                .orderTaxiNum(taxiSeatNum).taxiId(addressInfo.getTaxiId())
                .build();
        result = orderInfoService.save(orderInfo);
        // 创建打车订单用户关系
        DUserOrderRelation userOrderRelation = DUserOrderRelation.builder()
                .orderId(orderInfo.getOrderId()).mOpenId(mOpenId)
                .build();
        result = uoRelationService.save(userOrderRelation);
        if (result) {
            // 订单过期时间 默认一个小时
            DCommonCode commonCode = codeService.getCommonCodeByCode(CommonKey.ORDER_CREATE_TIME.getValue());
            long expireTime = 1;
            if (Objects.nonNull(commonCode)) {
                expireTime = Long.parseLong(commonCode.getContent());
            }
            long orderExpireTime = System.currentTimeMillis() + (expireTime * 1000);
            String orderKey = RedisKey.ORDER_INFO.getValue() + orderInfo.getOrderCode();
            // 返回值
            orderVo = TaxiOrderRep.builder().orderId(orderInfo.getOrderId())
                    .orderCode(orderInfo.getOrderCode()).orderPrice(orderInfo.getOrderPrice())
                    .orderStatus(orderInfo.getOrderStatus()).orderTaxiNum(orderInfo.getOrderTaxiNum())
                    .createTime(orderInfo.getCreateTime()).mOpenId(userOrderRelation.getMOpenId())
                    .orderEndTime(orderExpireTime).addressInfo(addressInfo).build();
            redisUtil.set(orderKey, JSONUtil.toJsonStr(orderVo), expireTime);
        }
        return DResult.of(orderVo);
    }

    /**
     * 司机接单/抢单接口
     *
     * @param orderReq
     * @return
     */
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "body", dataType = "TaxiOrderReq", dataTypeClass = TaxiOrderReq.class, name = "orderReq", value = "", required = true)
    })
    @ApiOperation(value = "司机接单/抢单接口", notes = "司机接单/抢单接口", httpMethod = "POST")
    @DistributedLock
    @PostMapping("/receivingTaxiOrder")
    public DResult receivingTaxiOrder(@RequestBody TaxiOrderReq orderReq) {
        this.verifyOrder(orderReq);
        // 更新订单状态;
        boolean flag = orderInfoService.updateOrderStatus(orderReq.getOrderId(), CommonKey.ORDER_STATUS_20.getValue());
        if (!flag) {
            throw new MuMuException("订单状态变更失败!");
        }
        // 更新用户订单关系;
        flag = orderInfoService.updateUserOrderRelation(orderReq.getOrderId(), orderReq.getDOpenId());
        if (flag) {
            return DResult.of(ResultCode.ORDER_RECEIVING_SUCCESS.getCode(), ResultCode.ORDER_RECEIVING_SUCCESS.getMsg());
        } else {
            throw new MuMuException("用户订单关系变更失败!");
        }
    }

    /**
     * 司机抵达出发点/乘客上车接口
     *
     * @param orderReq
     * @return
     */
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "body", dataType = "TaxiOrderReq", dataTypeClass = TaxiOrderReq.class, name = "orderReq", value = "", required = true)
    })
    @ApiOperation(value = "司机抵达出发点/乘客上车接口", notes = "司机抵达出发点/乘客上车接口", httpMethod = "POST")
    @DistributedLock
    @PostMapping("/arriveFirstTaxiOrder")
    public DResult arriveFirstTaxiOrder(@RequestBody TaxiOrderReq orderReq) {
        this.verifyOrder(orderReq);
        // 更新订单状态;
        boolean flag = orderInfoService.updateOrderStatus(orderReq.getOrderId(), CommonKey.ORDER_STATUS_30.getValue());
        if (flag) {
            return DResult.success();
        } else {
            throw new MuMuException("订单状态变更失败!");
        }
    }

    /**
     * 司机已接到乘客/行驶中接口
     *
     * @param orderReq
     * @return
     */
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "body", dataType = "TaxiOrderReq", dataTypeClass = TaxiOrderReq.class, name = "orderReq", value = "", required = true)
    })
    @ApiOperation(value = "司机已接到乘客/行驶中接口", notes = "司机已接到乘客/行驶中接口", httpMethod = "POST")
    @DistributedLock
    @PostMapping("/arriveRunTaxiOrder")
    public DResult arriveRunTaxiOrder(@RequestBody TaxiOrderReq orderReq) {
        this.verifyOrder(orderReq);
        // 更新订单状态;
        boolean flag = orderInfoService.updateOrderStatus(orderReq.getOrderId(), CommonKey.ORDER_STATUS_40.getValue());
        if (flag) {
            return DResult.success();
        } else {
            throw new MuMuException("订单状态变更失败!");
        }
    }

    /**
     * 司机抵达目的接口
     *
     * @param orderReq
     * @return
     */
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "body", dataType = "TaxiOrderReq", dataTypeClass = TaxiOrderReq.class, name = "orderReq", value = "", required = true)
    })
    @ApiOperation(value = "司机抵达目的接口", notes = "司机抵达目的接口", httpMethod = "POST")
    @DistributedLock
    @PostMapping("/arriveLastTaxiOrder")
    public DResult arriveLastTaxiOrder(@RequestBody TaxiOrderReq orderReq) {
        this.verifyOrder(orderReq);
        // 更新订单状态;
        boolean flag = orderInfoService.updateOrderStatus(orderReq.getOrderId(), CommonKey.ORDER_STATUS_50.getValue());
        if (flag) {
            return DResult.success();
        } else {
            throw new MuMuException("订单状态变更失败!");
        }
    }

    /**
     * 司机/乘客取消订单接口
     *
     * @param orderReq
     * @return
     */
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "body", dataType = "TaxiOrderReq", dataTypeClass = TaxiOrderReq.class, name = "orderReq", value = "", required = true)
    })
    @ApiOperation(value = "司机/乘客取消订单接口", notes = "司机/乘客取消订单接口", httpMethod = "POST")
    @DistributedLock
    @PostMapping("/cancelTaxiOrder")
    public DResult cancelTaxiOrder(@RequestBody TaxiOrderReq orderReq) {
        this.verifyOrder(orderReq);
        // 更新订单状态;
        boolean flag = orderInfoService.updateOrderStatus(orderReq.getOrderId(), CommonKey.ORDER_STATUS_80.getValue());
        if (flag) {
            return DResult.success();
        } else {
            throw new MuMuException("订单状态变更失败!");
        }
    }

    /**
     * 关闭订单接口
     *
     * @param orderReq
     * @return
     */
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "body", dataType = "TaxiOrderReq", dataTypeClass = TaxiOrderReq.class, name = "orderReq", value = "", required = true)
    })
    @ApiOperation(value = "关闭订单接口", notes = "关闭订单接口", httpMethod = "POST")
    @DistributedLock
    @PostMapping("/closeTaxiOrder")
    public DResult closeTaxiOrder(@RequestBody TaxiOrderReq orderReq) {
        this.verifyOrder(orderReq);
        // 更新订单状态;
        boolean flag = orderInfoService.updateOrderStatus(orderReq.getOrderId(), CommonKey.ORDER_STATUS_70.getValue());
        if (flag) {
            return DResult.success();
        } else {
            throw new MuMuException("订单状态变更失败!");
        }
    }

    /**
     * 订单数据验证
     *
     * @param orderReq
     */
    private void verifyOrder(TaxiOrderReq orderReq) {
        // 获取订单信息
        if (Objects.isNull(orderReq)) {
            throw new MuMuException("参数为空!");
        }
        DTaxiOrderInfo orderInfo = orderInfoService.getOrderInfo(orderReq.getOrderId());
        if (Objects.isNull(orderInfo)) {
            throw new MuMuException("订单不存在!");
        }
        orderReq.setOrderCode(orderInfo.getOrderCode());
        if (!orderReq.getOrderStatus().equals(orderInfo.getOrderStatus())) {
            throw new MuMuException("订单已被处理!");
        }
    }

}
